/* echo_tcp_sv.c

   A server that receives datatream。

   See also echo_tcp_cl.c.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> /*for bzero*/
#include <unistd.h>

#include "echo_tcp.h"

static void errExit(char *msg) {
  perror(msg);
  exit(EXIT_FAILURE);
}

size_t readn(int fd, void *buffer, size_t size) {
  char *buffer_pointer = buffer;
  int length = size;

  while (length > 0) {
    int result = read(fd, buffer_pointer, length);

    if (result < 0) {
      if (errno == EINTR)
        continue; /* 考虑非阻塞的情况，这里需要再次调用read */
      else
        return (-1);
    } else if (result == 0)
      break; /* EOF(End of File)表示套接字关闭 */

    length -= result;
    buffer_pointer += result;
  }
  return (size - length); /* 返回的是实际读取的字节数*/
}

int main(int argc, char *argv[]) {
#ifdef IPV6
  struct sockaddr_in6 svaddr, claddr;
#else
  struct sockaddr_in svaddr, claddr;
#endif

  int listenfd, connfd, j;
  ssize_t numBytes;
  socklen_t len;
  char buf[BUF_SIZE];
  char claddrStr[INET6_ADDRSTRLEN];

#ifdef IPV6
  /* Create a datagram socket bound to an address in the IPv6 domain */
  listenfd = socket(AF_INET6, SOCK_STREAM, 0);
  if (listenfd == -1) errExit("socket");

  memset(&svaddr, 0, sizeof(struct sockaddr_in6));
  svaddr.sin6_family = AF_INET6;
  svaddr.sin6_addr = in6addr_any; /* Wildcard address */
  svaddr.sin6_port = htons(PORT_NUM);
#else
  listenfd = socket(AF_INET, SOCK_STREAM, 0);
  if (listenfd == -1) errExit("socket");

  bzero(&svaddr, sizeof(svaddr));
  svaddr.sin_family = AF_INET;
  svaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Wildcard address */
  svaddr.sin_port = htons(PORT_NUM);
#endif
  if (bind(listenfd, (struct sockaddr *)&svaddr, sizeof(svaddr)) == -1) {
    errExit("bind");
  }

  /* set backlog 1024 */
  if (listen(listenfd, 1024) == -1) {
    errExit("listen");
  }

  for (;;) {
    len = sizeof(claddr);
    printf("waiting for connect...\n");
    connfd = accept(listenfd, (struct sockaddr *)&claddr, &len);
    if (connfd <= 0) {
      fprintf(stderr, "accept fail");
    }

    if (NULL ==
        inet_ntop(AF_INET, &claddr.sin_addr, claddrStr, INET_ADDRSTRLEN)) {
      printf("Couldn't convert client address to string\n");
    } else {
      printf("client (%s, %u) connected\n", claddrStr, ntohs(claddr.sin_port));
    }

    int nmsg = 0;
    int nread = read(connfd, &nmsg, sizeof(int));
    if (nread != sizeof(int)) {
      errExit("read len");
    }
    printf("recv msg len=[%d] \n", nmsg);

    bzero(buf, BUF_SIZE);
    nread = read(connfd, buf, nmsg);
    if (nread != nmsg) {
      errExit("read msg");
    }

    fprintf(stdout, "recv msg=[%s]\n\n", buf);

    close(connfd); /* 关闭连接套接字，注意不是监听套接字*/
  }
}